use anyhow::{anyhow, Result};
use ratatui::prelude::Rect;
use tokio::sync::oneshot::Sender;

use super::SELECT_PADDING;
use crate::{core::Position, misc::tty_size};

#[derive(Default)]
pub struct Select {
	title:    String,
	items:    Vec<String>,
	position: (u16, u16),

	offset:   usize,
	cursor:   usize,
	callback: Option<Sender<Result<usize>>>,

	pub visible: bool,
}

pub struct SelectOpt {  // 选择器初始化项
	pub title:    String,  // 选择器标题
	pub items:    Vec<String>, // 选项列表
	pub position: Position, // 显示位置
}

impl Select {

    // 显示选择器
	pub fn show(&mut self, opt: SelectOpt, tx: Sender<Result<usize>>) {
		self.close(false);

        // 初始化新状态
		self.title = opt.title;
		self.items = opt.items;
		self.position = match opt.position {
			Position::Coords(x, y) => (x, y), // 解析位置为具体坐标
			_ => unimplemented!(),
		};
		self.callback = Some(tx);  // 保存回调发送器
		self.visible = true; // 标记为可见
	}

	pub fn close(&mut self, submit: bool) -> bool {
		if let Some(cb) = self.callback.take() { // 取出回调发送器 避免重复发送
            // 发送结果
			let _ = cb.send(
                if submit {
                    Ok(self.cursor)
                } else {
                    Err(anyhow!("canceled"))
                }
            );
		}

        // 重置状态
		self.cursor = 0;
		self.offset = 0;
		self.visible = false; // 标记为不可见
		true
	}

	pub fn next(&mut self, step: usize) -> bool {
		let len = self.items.len();
		if len == 0 {
			return false;  // 没有item不进行光标的移动
		}

		let old = self.cursor;
		self.cursor = (self.cursor + step).min(len - 1);

        // 处理滚动  光标超出可见窗口  调整offset让光标可见
		let limit = self.limit(); // 可见区域最多显示的选项数
		if self.cursor >= len.min(self.offset + limit) {
            // 偏移量 = 最大偏移量 与 当前偏移+移动步长  的较小值
			self.offset = len.saturating_sub(limit).min(self.offset + self.cursor - old);
		}

		old != self.cursor  // 返回是否移动了光标
	}

	pub fn prev(&mut self, step: usize) -> bool {
		let old = self.cursor;
		self.cursor = self.cursor.saturating_sub(step);

        // 处理滚动 如果光标在当前可见窗口的上方 就调整offset使得光标可见
		if self.cursor < self.offset {
			self.offset = self.offset.saturating_sub(old - self.cursor); // 减少offset向上滚动
		}

		old != self.cursor
	}

	#[inline]
	pub fn window(&self) -> &[String] {
        // 获取当前可见的选项切片
		let end = (self.offset + self.limit()).min(self.items.len());
		&self.items[self.offset..end]
	}

    // 可见区域管理 select需要限制一次显示的选项数量  超出部分通过滚动查看
	#[inline]
	pub fn limit(&self) -> usize {
        // 可见item的数量
		self.items.len().min(tty_size().ws_row.saturating_sub(SELECT_PADDING).min(5) as usize)
	}
}

impl Select {
	#[inline]
    // 返回标题的克隆  供UI渲染标题栏使用
	pub fn title(&self) -> String { self.title.clone() }

	#[inline]
    // 返回光标在可见区的相对索引  用于UI高亮显示
	pub fn rel_cursor(&self) -> usize { self.cursor - self.offset }

	#[inline]
    // 返回选择器在终端的渲染区域  用于是ui框架确认绘制范围
	pub fn area(&self) -> Rect {
		Rect {
			x:      self.position.0, // 起始列
			y:      self.position.1 + 2, // 起始行
			width:  50,
			height: self.limit() as u16 + SELECT_PADDING,
		}
	}
}
